﻿using System.Diagnostics;
using System.Text.Json;
using System.Threading.Tasks;
using AutoMapper;
using MediatR;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using ORS.OrderRobot.IOC;
using ORS.OrderRobot.Service.Helper;
using ORS.OrderRobot.Service.Jobs;
using ORS.OrderRobot.ServiceContracts;
using ORS.OrderRobot.ServiceContracts.Dtos;
using ORS.OrderRobot.ServiceContracts.Dtos.Api;
using ORS.OrderRobot.ServiceContracts.ThridPartApi;
using Polly;

namespace ORS.OrderRobot.Service
{
	public class ShoppingService:IShoppingService,IScoped
	{
        private readonly ILogger<ShoppingService> _logger;
        private readonly IMapper _mapper;
        private readonly IBackgroundJobManager _backgroundJobManager;
        private readonly IHubContext<MessageHub> _hubContext;
        private readonly IThirdBasketService _thirdBasketService;
        private readonly IAccountService _accountService;
        private readonly IMediator _mediator;
        private readonly AccountCacheManager _accountCacheManager;
        private readonly LockCacheManager _lockCacheManager;
        private readonly IServiceProvider _serviceProvider;
        private readonly ISystemConfigService _systemConfigService;
        public ShoppingService(
            ILogger<ShoppingService> logger,
            IMapper mapper,
            IBackgroundJobManager backgroundJobManager,
            IHubContext<MessageHub> hubContext,
            IThirdBasketService thirdBasketService,
            IAccountService accountService,
            IMediator mediator,
            AccountCacheManager accountCacheManager,
            IServiceProvider serviceProvider,
            ISystemConfigService systemConfigService,
            LockCacheManager lockCacheManager
        )
		{
            _logger = logger;
            _mapper = mapper;
            _backgroundJobManager = backgroundJobManager;
            _hubContext = hubContext;
            _thirdBasketService = thirdBasketService;
            _accountService = accountService;
            _mediator = mediator;
            _accountCacheManager = accountCacheManager;
            _serviceProvider = serviceProvider;
            _systemConfigService = systemConfigService;
            _lockCacheManager = lockCacheManager;
        }
        /// <summary>
        /// 获取登录信息(缓存中不存在时，自动登录)
        /// </summary>
        private async Task<LoginResultInfo?> GetLoginedUserAsync(string email)
        {
            var loginResult = await _accountCacheManager.GetLogin(email);
            if(loginResult != null)
            {
                return loginResult;
            }
            using var scope = _serviceProvider.CreateScope();
            var accountTempService = scope.ServiceProvider.GetRequiredService<IAccountService>();
            var accountLoginTempService = scope.ServiceProvider.GetRequiredService<IAccountLoginService>();
            var account = await accountTempService.GetAccount(email);
            if (account.HasValue)
            {
                var (_, password) = account.Value;
                return await accountLoginTempService.LoginAsync(email, password);
            }
            return null;
        }
        /// <summary>
        /// 商品添加到购物车(失败根据配置自动重试)
        /// </summary>
        private async Task<BasketDto?> AddProductToBasketAsync(ShoppingInput input, CommonInput commonInput)
        {
            var systemConfig = await _systemConfigService.GetConfigAsync();
            var result = await RetryHelper.RetryWithFixAsync(
                () => _thirdBasketService.AddProductToBasket(input, commonInput),
                async (ex) =>
                {
                    var cartItem = input.Cart.First();
                    var email = input.Email;
                    if (ex.Code == 401)
                    {
                        try
                        {
                            await GetLoginedUserAsync(commonInput.Email);
                            return (true, 1);
                        }
                        catch
                        {
                            return (false, 1);
                        }
                    }
                    else if (ex.Code == 429)
                    {
                        await MsgHelper.SendAsync(_hubContext, new MsgData { Obj = email, Action = $"添加购物车限流,商品:{input.ProductName}", Type = Consts.ErrMsg });
                        return (false, 0);
                    }
                    else if (ex.Code == 503)
                    {
                        return (true, systemConfig.AutoShoppingTask.Retry);
                    }
                    else
                    {
                        return (false, 0);
                    }
                },
                onRetry: async (retryCount, exception) =>
                {
                    var cartItem = input.Cart.First();
                    await MsgHelper.SendAsync(_hubContext, new MsgData { Obj = input.Email, Action = $"添加购物车第{retryCount}次重试,商品:{input.ProductName}", Type = Consts.ErrMsg });
                    _logger.LogError(exception, "添加购物车失败,账号: {email},第{retryCount}次重试,购物车信息:{cart}", input.Email, retryCount, JsonSerializer.Serialize(input.Cart));
                });
            return result;
        }
        /// <summary>
        /// 设置航班信息
        /// </summary>
        private async Task SetFlightAsync(AccountBoardingDto boardingDto, CommonInput commonInput)
        {
            var depatureInput = _mapper.Map<DepatureInput>(boardingDto);
            await _thirdBasketService.SetFlight(depatureInput, commonInput);
        }
        /// <summary>
        /// 设置收货地址
        /// </summary>
        private async Task SetShipmentsAsync(LoginResultInfo loginedUser, CommonInput commonInput)
        {
            var shipmentInput = new ShipmentInput
            {
                shipping_address = new ShippingAddressInput
                {
                    first_name = loginedUser.FirstName,
                    last_name = loginedUser.LastName,
                    phone = loginedUser.PhoneMobile,
                }
            };
            await _thirdBasketService.SetShipments(shipmentInput, commonInput);
        }
        /// <summary>
        /// 设置账单地址
        /// </summary>
        private async Task SetBillingAddressAsync(LoginResultInfo loginedUser, CommonInput commonInput)
        {
            var billingAddressInput = new BillingAddressInput
            {
                first_name = loginedUser.FirstName,
                last_name = loginedUser.LastName,
                phone = loginedUser.PhoneMobile,
            };
            await _thirdBasketService.SetBillingAddress(billingAddressInput, commonInput);
        }
        /// <summary>
        /// 设置支付方式(经实验，必须依赖账单地址)
        /// </summary>
        private async Task SetPaymentAsync(CommonInput commonInput)
        {
            await _thirdBasketService.SetPayment(new PaymentInput { }, commonInput);
        }
        /// <summary>
        /// 生成订单（失败自动重试）
        /// </summary>
        private async Task<OrderResDto> SetOrderAsync(LoginResultInfo loginedUser,CommonInput commonInput)
        {
            var systemConfig = await _systemConfigService.GetConfigAsync();
            var bizInput = new OrdersInput { basket_id = loginedUser.BasketId };
            var res = await RetryHelper.RetryWithFixAsync(
                ()=> _thirdBasketService.CreateOrder(bizInput, commonInput),
                async (ex) => {
                    if (ex.Code == 429)
                    {
                        await Task.CompletedTask;
                        return (false, 0);
                    }
                    if (ex.Code == 503)
                    {
                        await Task.CompletedTask;
                        return (true, systemConfig.AutoShoppingTask.Retry);
                    }
                    else
                    {
                        return (false, 0);
                    }
                },
                onRetry: async (retryCount, exception) =>
                {
                    await MsgHelper.SendAsync(_hubContext, new MsgData { Obj = commonInput.Email, Action = $"创建订单繁忙，第{retryCount}次重试，", Type = Consts.ErrMsg });
                });
            return res;
        }
        /// <summary>
        /// 创建购物车
        /// </summary>
        private async Task<BasketDto> CreateBasketAsync(LoginResultInfo loginedUser, CommonInput commonInput)
        {
            var updateBasketInput = new CreateBasketInput
            {
                customer_info = new BasketUserInfo
                {
                    customer_id = loginedUser.CustomerId,
                    customer_no = loginedUser.CustomerNo,
                    customer_name = $"{loginedUser.FirstName} {loginedUser.LastName}",
                    email = loginedUser.Email,
                }
            };
            var dto = await _thirdBasketService.CreateBasket(updateBasketInput, commonInput);
            return dto;
        }
        /// <summary>
        /// 推送订单更新任务
        /// </summary>
        /// <param name="boardingDto"></param>
        /// <param name="orderNo"></param>
        /// <param name="cart"></param>
        /// <returns></returns>
        private async Task EnqueueOrderUpdateJobAsync(AccountBoardingDto boardingDto, string orderNo, List<ProductToBasketInput> cart)
        {
            await _backgroundJobManager.EnqueueAsync<UpdateOrderJob, UpdateOrderArgs>(new UpdateOrderArgs
            {
                AccountId = boardingDto.AccountId,
                BoardingId = boardingDto.Id,
                OrderNo = orderNo,
                CreateTime = DateTime.Now.China(),
                Cart = cart,
            });
        }
        /// <summary>
        /// 从购物车中删除商品
        /// </summary>
        /// <param name="input"></param>
        /// <param name="commonInput"></param>
        /// <returns></returns>
        private async Task RemoveProductFromBasket(ShoppingInput input,CommonInput commonInput)
        {
            //删除购物车中的项目，防止累加
            try
            {
                var basket = await _thirdBasketService.GetBasketDetail(commonInput);
                var itemId = basket.ProductItems?.Find(x => x.product_id == input.Cart.First().product_id)?.item_id;
                if (!string.IsNullOrEmpty(itemId))
                {
                    await _thirdBasketService.RemoveBasketItem(itemId, commonInput);
                }
            }
            catch(Exception e)
            {
                _logger.LogError(e, $"删除购物车失败,{commonInput.Email}");
                await MsgHelper.SendAsync(_hubContext,new MsgData { Obj = commonInput.Email, Action = "删除购物车失败"});
            }
        }
        /// <summary>
        /// 修复购物车中的用户信息
        /// </summary>
        /// <param name="loginedUser"></param>
        /// <param name="commonInput"></param>
        /// <returns></returns>
        private async Task FixBasketCustomerInfoAsync(LoginResultInfo loginedUser, CommonInput commonInput)
        {
            var input = new BasketCustomerInput
            {
                customer_id = loginedUser.CustomerId,
                customer_name = $"{loginedUser.LastName} {loginedUser.FirstName}",
                customer_no = loginedUser.CustomerNo,
                email = loginedUser.Email,
            };
            try
            {
                await _thirdBasketService.SetBasketCustomerInfo(input,commonInput);
            }
            catch
            {
                await MsgHelper.SendAsync(_hubContext, new MsgData {
                    Obj = commonInput.Email,
                    Action = $"购物车用户信息修复失败",
                    Type = Consts.ErrMsg
                });
            }
        }
        /// <summary>
        /// 获取下单上下文（含用户、登机、缓存key等）
        /// </summary>
        private async Task<ShoppingContext> GetShoppingContextAsync(string email)
        {
            var context = new ShoppingContext();
            var loginedUser = await GetLoginedUserAsync(email);
            if (loginedUser == null)
            {
                var message = $"无法获取{email}的登录信息";
                _logger.LogError(message);
                await MsgHelper.SendAsync(_hubContext, new MsgData { Obj = email, Action = "无法获取登录信息", Type = Consts.ErrMsg});
                throw new Exception(message);
            }
            var boardingDto = await _accountService.GetBoardingAsync(email);
            if (boardingDto == null)
            {
                var message = $"无法获取{email}的登机信息";
                _logger.LogError(message);
                await MsgHelper.SendAsync(_hubContext, new MsgData { Obj = email, Action = "无法读取数据库中的登机信息", Type = Consts.ErrMsg });
                throw new Exception(message);
            }
            var commonInput = new CommonInput
            {
                BasketId = loginedUser.BasketId,
                Email = loginedUser.Email,
                Token = loginedUser.Token
            };
            context.LoginedUser = loginedUser;
            context.BoardingDto = boardingDto;
            context.CommonInput = commonInput;
            return context;
        }
        /// <summary>
        /// 添加购物车后主流程（智能调用、下单、重建购物车、推送任务等）
        /// </summary>
        private async Task DoShoppingAfterBasketAsync(ShoppingInput input, ShoppingContext ctx, BasketDto? basketResult)
        {
            var timeWatch = new Stopwatch();
            timeWatch.Start();
            try
            {
                // 智能调用API，失败自动重试2次
                var smartCallRetryPolicy = Policy
                    .Handle<Exception>()
                    .RetryAsync(2, async (exception, retryCount, context) =>
                    {
                        await MsgHelper.SendAsync(_hubContext, new MsgData { Obj = input.Email, Action = $"魔法代码调用失败，重试{retryCount},商品:{input.ProductName}", Type = Consts.ErrMsg });
                    });
                await smartCallRetryPolicy.ExecuteAsync(async () =>
                {
                    await SmartCallApiByBasketRes(basketResult, ctx);
                });

                var orderRes = await SetOrderAsync(ctx.LoginedUser, ctx.CommonInput);
                if (orderRes == null)
                {
                    throw new Exception("订单响应内容为空，获取不到订单号");
                }
                timeWatch.Stop();
                await _accountCacheManager.SetOrder(input.Email, orderRes.order_no);
                await MsgHelper.SendAsync(_hubContext, new MsgData { Obj = input.Email, Action = $"创建订单成功,商品:{input.ProductName}",UsedTime = timeWatch.ElapsedMilliseconds });
                _logger.LogInformation($"创建订单成功。{input.Email},商品:{input.ProductName},整体用时:{timeWatch.ElapsedMilliseconds} ms");
                //跟小程序保持一致，订单创建成功后重新创建订单
                try
                {
                    //todo:万一此时有其他进程刚刚让用户重登录了怎么办
                    var newBasket = await CreateBasketAsync(ctx.LoginedUser, ctx.CommonInput);
                    var latestLoginUser = await _accountCacheManager.GetLogin(input.Email);
                    if (latestLoginUser != null)
                    {
                        latestLoginUser.BasketId = newBasket.BasketId;
                        await _accountCacheManager.SetLogin(input.Email, latestLoginUser);
                    }
                }
                catch (Exception ex)
                {
                    await MsgHelper.SendAsync(_hubContext, new MsgData { Obj = input.Email, Action = $"重新创建购物车异常,商品:{input.ProductName}", Type = Consts.ErrMsg });
                    _logger.LogError(ex, "重新创建购物车异常");
                }
                await EnqueueOrderUpdateJobAsync(ctx.BoardingDto, orderRes.order_no, input.Cart);
            }
            catch (Exception e)
            {
                timeWatch.Stop();
                await RemoveProductFromBasket(input, ctx.CommonInput);
                await MsgHelper.SendAsync(_hubContext, new MsgData { Obj = input.Email, Action = $"创建订单失败。商品:{input.ProductName}", UsedTime = timeWatch.ElapsedMilliseconds, Type = Consts.ErrMsg });
            }
        }
        /// <summary>
        /// 智能调用接口
        /// </summary>
        /// <param name="basket"></param>
        /// <param name="ctx"></param>
        /// <returns></returns>
        private async Task SmartCallApiByBasketRes(BasketDto? basket, ShoppingContext ctx)
        {
            var lockKey = ctx.CommonInput.Email;
            var lockValue = Guid.NewGuid().ToString();
            var pollInterval = 60;
            var maxWaitTime = 2* 60 * 1000;
            var waited = 0;

            // while轮询加锁，轮询间隔递减
            while (true)
            {
                var existingLock = await _lockCacheManager.GetShopDepLock(lockKey);
                if (string.IsNullOrEmpty(existingLock))
                {
                    await _lockCacheManager.SetShopDepLock(lockKey, lockValue, maxWaitTime);
                    break;
                }
                await Task.Delay(pollInterval);
                waited += pollInterval;
                if (waited >= maxWaitTime)
                {
                    // 超时直接返回
                    return;
                }
            }

            try
            {
                if (basket == null) return;
                var tasks = new List<Task>();
                // 检查用户信息
                if (basket.customer_info?.email == null || string.IsNullOrEmpty(basket.customer_info.email))
                {
                    tasks.Add(FixBasketCustomerInfoAsync(ctx.LoginedUser, ctx.CommonInput));
                }
                //// 检查航班信息
                if (string.IsNullOrEmpty(basket.c_flightDetails))
                {
                    tasks.Add(SetFlightAsync(ctx.BoardingDto, ctx.CommonInput));
                }
                // 检查账单地址
                if (string.IsNullOrEmpty(basket.billing_address?.country_code))
                {
                    tasks.Add(SetBillingAddressAsync(ctx.LoginedUser, ctx.CommonInput));
                }
                //支付方式
                if(basket.payment_instruments == null || !basket.payment_instruments.Any(x=>x.payment_method_id == "Instore_Payment"))
                {
                    tasks.Add(SetPaymentAsync(ctx.CommonInput));
                }
                // 检查收货信息 - 简化逻辑
                var needSetShipments = basket.shipments == null || 
                                      !basket.shipments.Any() ||
                                      basket.shipments[0]?.shipping_address == null ||
                                      string.IsNullOrEmpty(basket.shipments[0].shipping_address.first_name) ||
                                      basket.shipments[0]?.shipping_method == null ||
                                      string.IsNullOrEmpty(basket.shipments[0].shipping_method.id);    
                if (needSetShipments)
                {
                    tasks.Add(SetShipmentsAsync(ctx.LoginedUser, ctx.CommonInput));
                }
                if (tasks.Any())
                {
                    var timeWatch = new Stopwatch();
                    timeWatch.Start();
                    await MsgHelper.SendAsync(_hubContext, new MsgData { Obj = ctx.CommonInput.Email, Action = $"模法代码块执行开始,大小:{tasks.Count}" });

                    await Task.WhenAll(tasks);
                    timeWatch.Stop();
                    await MsgHelper.SendAsync(_hubContext, new MsgData { Obj = ctx.CommonInput.Email, Action = $"模法代码块执行完成",UsedTime = timeWatch.ElapsedMilliseconds });
                }
            }
            finally
            {
                try
                {
                    var currentLock = await _lockCacheManager.GetShopDepLock(lockKey);
                    if (currentLock == lockValue)
                    {
                        await _lockCacheManager.RemoveShopDepLock(lockKey);
                    }
                }
                catch (Exception ex)
                {
                    await MsgHelper.SendAsync(_hubContext, new MsgData { Obj = ctx.CommonInput.Email, Action = $"模法代码块锁释放失败", Type = Consts.ErrMsg });
                    _logger.LogError(ex, $"释放用户 {ctx.CommonInput.Email} 下单锁时发生异常");
                }
            }
        }

        /// <summary>
        /// 正常的自动下单模式
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public async Task ShoppingAsync(ShoppingInput input)
        {
            var ctx = await GetShoppingContextAsync(input.Email);
            var hasTodayOrder = await _accountCacheManager.HasOrder(input.Email);
            if (hasTodayOrder)
            {
                await MsgHelper.SendAsync(_hubContext, new MsgData { Obj = input.Email, Action = $"已经存在订单了,放弃抢购" });
                _logger.LogInformation("{email}今天已经存在订单了,放弃抢购", input.Email);
                return;
            }
            var basketResult = await AddProductToBasketAsync(input, ctx.CommonInput);
            await DoShoppingAfterBasketAsync(input, ctx, basketResult);
        }
        /// <summary>
        /// 试探性添加购物车并下单
        /// </summary>
        public async Task TryAddBasket(ShoppingInput input)
        {
            var productId = input.Cart.First().product_id;
            var productName = input.ProductName;
            var excludeEmail = new string[] { input.Email };
            var loginedUser = await _accountCacheManager.GetLogin(input.Email);
            //防止当前用户登录失效，导致所有用户都错过抢购，万一此时有商品就无语了
            if (loginedUser == null)
            {
                _ = _mediator.Publish(new PurchaseEvent(productId, productName, excludeEmail));
                await GetLoginedUserAsync(input.Email);
            }

            var ctx = await GetShoppingContextAsync(input.Email);
            BasketDto? basketResult = null;
            bool notified401 = false;
            try
            {
                basketResult = await RetryHelper.RetryWithFixAsync(
                    operation: () => _thirdBasketService.AddProductToBasket(input, ctx.CommonInput),
                    handleFixWithRetryCount: async (ex) =>
                    {
                        if (ex.Code == 401)
                        {
                            if (!notified401)
                            {
                                _ = _mediator.Publish(new PurchaseEvent(productId, productName, excludeEmail));
                                notified401 = true;
                            }
                            await GetLoginedUserAsync(input.Email);
                            return (true, 1);
                        }
                        else if (ex.Code == 503)
                        {
                            _ = _mediator.Publish(new PurchaseEvent(productId, productName, excludeEmail));
                            return (true, 1);
                        }
                        // 其它异常不重试
                        return (false, 0);
                    }
                );
            }
            catch
            {
                return;
            }
            if (basketResult == null) return;
            //加入购物车，通知其他用户
            _ = _mediator.Publish(new PurchaseEvent(productId, productName, excludeEmail));
            await DoShoppingAfterBasketAsync(input, ctx, basketResult);
        }
        /// <summary>
        /// 下单依赖信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public async Task SetShoppingDepInfoAsync(string email)
        {
            var timeWatch = new Stopwatch();
            timeWatch.Start();
            try
            {
                var ctx = await GetShoppingContextAsync(email);
                var tasks = new List<Task>
                {
                    SetFlightAsync(ctx.BoardingDto, ctx.CommonInput),
                    SetShipmentsAsync(ctx.LoginedUser, ctx.CommonInput),
                    SetBillingAddressAsync(ctx.LoginedUser, ctx.CommonInput),
                    FixBasketCustomerInfoAsync(ctx.LoginedUser, ctx.CommonInput),
                };
                var basketDto = await _thirdBasketService.GetBasketDetail(
                    new CommonInput
                    {
                        BasketId = ctx.CommonInput.BasketId,
                        Token = ctx.CommonInput.Token,
                        Email = ctx.CommonInput.Email
                    }
                );
                if (basketDto.payment_instruments == null || !basketDto.payment_instruments.Any(x => x.payment_method_id == "Instore_Payment"))
                {
                    tasks.Add(SetPaymentAsync(ctx.CommonInput));
                }
                await Task.WhenAll(tasks);
                timeWatch.Stop();
                await MsgHelper.SendAsync(_hubContext, new MsgData { Obj = email, Action = $"依赖前置信息执行完成",UsedTime = timeWatch.ElapsedMilliseconds });
            }
            catch (Exception e)
            {
                timeWatch.Stop();
                await MsgHelper.SendAsync(_hubContext, new MsgData { Obj = email, Action = $"依赖前置信息执行失败", UsedTime = timeWatch.ElapsedMilliseconds,Type = Consts.ErrMsg });
                _logger.LogError(e, $"下单依赖设置失败,用时:{timeWatch.ElapsedMilliseconds}ms");
                throw;
            }
        }
    }
}

